package cn.gjxblog.transaction;


import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
import org.junit.Before;
import org.junit.Test;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.transaction.support.TransactionTemplate;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;

/**
 * 编程式事务(忽略连接关闭处理步骤)
 */
public class CodeTransactionTests {

   private DataSource dataSource;

    @Before
    public void before() throws ClassNotFoundException, SQLException {
        String name ="root";
        String pwd="123456";
        int port = 3306;
        String hostName = "mysql.db.gjxblog.cn";

         dataSource = new MysqlDataSource();
        ((MysqlDataSource) dataSource).setUser(name);
        ((MysqlDataSource) dataSource).setPassword(pwd);
        ((MysqlDataSource) dataSource).setServerName(hostName);
        ((MysqlDataSource) dataSource).setPort(port);
        ((MysqlDataSource) dataSource).setDatabaseName("test");
    }

    /**
     * 使用JDBC 底层API完成对事务的控制
     */
    @Test
    public void test1() throws SQLException {
        Connection connection = dataSource.getConnection();
        //关闭事务自动提交
        connection.setAutoCommit(false);
        try {
            Statement statement = connection.createStatement();
            statement.execute("insert into user (`name`,`age`) values ('Jack',22)");
            int i = 10/0;
            connection.commit();// 事务提交
        } catch (SQLException e) {
            e.printStackTrace();
            connection.rollback();// 事务回滚
        }
    }

    /**
     * 借用Spring的 PlatformTransactionManager 事务管理器完成编程式事务
     */
    @Test
    public void test2() throws SQLException {
        PlatformTransactionManager transactionManager = new DataSourceTransactionManager(dataSource);
        // 根据
        TransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
        //@1963
        TransactionStatus transaction = transactionManager.getTransaction(transactionDefinition);
        try {
            // 这一步非常关键：上面几步操作后，事务管理器将获取的数据库连接和当前线程绑定，因此这里不能重新获取连接，只能从线程上下文去取
            // Spring提供了专门的DataSourceUtils工具方便操作。
            Statement statement = DataSourceUtils.getConnection(dataSource).createStatement();
            statement.execute("insert into user (`name`,`age`) values ('Mack',22)");
            int i = 10/0;
            transactionManager.commit(transaction);
        } catch (SQLException e) {
            e.printStackTrace();
            transactionManager.rollback(transaction);
        }
    }

    /**
     * 采用Spring提供的TransactionTemplate完成编程式事务
     */
    @Test
    public void test3(){
        PlatformTransactionManager transactionManager = new DataSourceTransactionManager(dataSource);

        TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
        transactionTemplate.execute(status -> {
            Statement statement = null;
            try {
                statement = DataSourceUtils.getConnection(dataSource).createStatement();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            try {
                statement.execute("insert into user (`name`,`age`) values ('July',22)");
            } catch (SQLException e) {
                e.printStackTrace();
            }
            int i = 10/0;
            return null;
        });
    }
}
